package com.bobbygu.libnet.common;

import android.util.Log;
import android.util.SparseArray;

import com.bobbygu.libnet.BuildConfig;
import com.bobbygu.libnet.utils.HttpsUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLSocketFactory;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * Api
 * <p>
 * author: 顾博君 <br>
 * time:   2016/12/19 14:20 <br>
 * e-mail: gubojun@csii.com.cn <br>
 * </p>
 */

public class Api {
    //读超时长，单位：毫秒
    private static final int READ_TIME_OUT = 60000;
    //连接时长，单位：毫秒
    private static final int CONNECT_TIME_OUT = 60000;
    private Retrofit mRetrofit;
    private ApiService mService;
    private ProgressListener progressListener;
    private static SparseArray<Api> sRetrofitManager = new SparseArray<>(HostType.TYPE_COUNT);
    /*************************缓存设置*********************/
/*
    1. noCache 不使用缓存，全部走网络

    2. noStore 不使用缓存，也不存储缓存

    3. onlyIfCached 只使用缓存

    4. maxAge 设置最大失效时间，失效则不使用 需要服务器配合

    5. maxStale 设置最大失效时间，失效则不使用 需要服务器配合 感觉这两个类似 还没怎么弄清楚，清楚的同学欢迎留言

    6. minFresh 设置有效时间，依旧如上

    7. FORCE_NETWORK 只走网络

    8. FORCE_CACHE 只走缓存*/

    /**
     * 设缓存有效期为两天
     */
    private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;
    /**
     * 查询缓存的Cache-Control设置，为if-only-cache时只查询缓存而不会请求服务器，max-stale可以配合设置缓存失效时间
     * max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值，那么客户机可接收超出超时期指定值之内的响应消息。
     */
    private static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;
    /**
     * 查询网络的Cache-Control设置，头部Cache-Control设为max-age=0
     * (假如请求了服务器并在a时刻返回响应结果，则在max-age规定的秒数内，浏览器将不会发送对应的请求到服务器，数据由缓存直接返回)时则不会使用缓存而请求服务器
     */
    private static final String CACHE_CONTROL_AGE = "max-age=0";

    /**
     * 创建日志拦截器
     *
     * @param level 日志级别
     * @return HttpLoggingInterceptor
     */
    private HttpLoggingInterceptor buildHttpLoggingInteceptor(HttpLoggingInterceptor.Level level) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.d("AFUBANK_LOG_API", message);
            }
        });
        interceptor.setLevel(level);
        return interceptor;
    }

    public static Api getApi(int hostType) {
        return sRetrofitManager.get(hostType);
    }

    //构造方法私有
    private Api(int hostType) {
        //缓存
//        File cacheFile = new File(WXApplication.getInstance().getCacheDir(), Constant.cacheDir);
//        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb

        SSLSocketFactory sslSocketFactory = HttpsUtil.getSslSocketFactory(null, null, null);
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)//读取超时时间
                .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)//连接超时时间
                .writeTimeout(120, TimeUnit.SECONDS)//写入超时时间120s
                .addInterceptor(mRewriteCacheControlInterceptor)
                .addNetworkInterceptor(mRewriteCacheControlInterceptor)
//                .addNetworkInterceptor(mProgressInterceptor)
                .addInterceptor(buildHttpLoggingInteceptor(HttpLoggingInterceptor.Level.BODY))
//                .cache(cache)
                //cookie管理
//                .cookieJar(CookiesManager.getInstance())
                .hostnameVerifier(BuildConfig.DEBUG ?
                        org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER :
                        org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER)
                .sslSocketFactory(sslSocketFactory);
        if (hostType == HostType.DOWNLOAD_HOST)
            builder.addNetworkInterceptor(mProgressInterceptor);
        OkHttpClient okHttpClient = builder.build();

        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .serializeNulls()
                .create();
        mRetrofit = new Retrofit.Builder()
                .client(okHttpClient)
//                .addConverterFactory(GsonConverterFactory.create(gson))
                .addConverterFactory(HostType.PRODUCT_UNENCRYPTION_HOST == hostType ?
                        UnencryptionConverterFactory.create(gson) :
                        EncryptionConverterFactory.create(gson)
                )
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(ApiConstants.getHost(hostType))
                .build();
        mService = mRetrofit.create(ApiService.class);
    }

    public static void removeAll() {
        sRetrofitManager.removeAtRange(0, sRetrofitManager.size());
    }

    /**
     * @param hostType
     */
    public static ApiService getDefault(int hostType) {
        Api retrofitManager = sRetrofitManager.get(hostType);
        if (retrofitManager == null) {
            retrofitManager = new Api(hostType);
            sRetrofitManager.put(hostType, retrofitManager);
        }
        return retrofitManager.mService;
    }

    public static ApiService getDefault() {
        return getDefault(HostType.PRODUCT_HOST);
    }

    public static ApiService getDefault(boolean encryption) {
        if (encryption) {
            return getDefault(HostType.PRODUCT_HOST);
        } else {
            return getDefault(HostType.PRODUCT_UNENCRYPTION_HOST);
        }
    }

    private final Interceptor mProgressInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            return response.newBuilder().body(new ProgressResponseBody(response.body(),
                    new ProgressResponseListener() {
                        @Override
                        public void onResponseProgress(long bytesRead, long contentLength, boolean done) {
//                            final int result = (int) (100 * bytesRead / contentLength);
                            if (progressListener != null) {
//                                LogUtils.logd("LC", contentLength + "----->" + bytesRead);
                                progressListener.onResponseProgress(bytesRead, contentLength, done);
                            }
                        }
                    }
            )).build();
        }
    };


    /**
     * 云端响应头拦截器，用来配置缓存策略
     * Dangerous interceptor that rewrites the server's cache-control header.
     */
    private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            HttpUrl originalHttpUrl = originalRequest.url();
            HttpUrl.Builder builder = originalHttpUrl.newBuilder();

            HttpUrl url = builder.build();
            Request.Builder requestBuilder = originalRequest.newBuilder()
                    .url(url)
                    .method(originalRequest.method(), originalRequest.body());
            Request request = requestBuilder.build();

//            if ("".equals(DeviceUtil.getNetWork(WXApplication.getInstance()))) {
//                request = request.newBuilder()
//                        .cacheControl(CacheControl.FORCE_CACHE)
//                        .build();
//            }
            Response originalResponse = chain.proceed(request);
//            if (!"".equals(DeviceUtil.getNetWork(WXApplication.getInstance()))) {
            //有网的时候读接口上的@Headers里的配置，你可以在这里进行统一的设置
            String cacheControl = request.cacheControl().toString();
            return originalResponse.newBuilder()
                    .header("Cache-Control", cacheControl)
                    .removeHeader("Pragma")
                    .build();
//            } else {
//                return originalResponse.newBuilder()
//                        .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_SEC)
//                        .removeHeader("Pragma")
//                        .build();
//            }
        }
    };

    public void setProgressListener(ProgressListener mProgressListener) {
        progressListener = mProgressListener;
    }

    public interface ProgressListener {
        void onResponseProgress(long bytesRead, long contentLength, boolean done);
    }
}
